﻿using libsvm;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace TFIDFExample
{
    class Program
    {
        static int nonspamNumber = 0;

        static void Main(string[] args)
        {
            int correct = 0;
            int total = 0;

            //CreateProblemFile("problemFile.txt");

            var svm = TrainSVM("problemFile.txt");
            
            TFIDF.Load();

            List<List<KeyValuePair<int, double>>> vectorSearchText = CreateTestVectors();

            List<svm_node> x = new List<svm_node>();
            foreach (var line in vectorSearchText)
            {
                x.Clear();

                foreach (var entity in line)
                {
                    x.Add(new svm_node() { index = entity.Key, value = entity.Value });
                }

                double val = svm.Predict(x.ToArray());
                if (nonspamNumber > 0 && val == 1)
                    correct++;
                else if (nonspamNumber <= 0 && val == -1)
                    correct++;

                nonspamNumber--;
                total++;
            }

            Console.WriteLine("Correct classified" + correct);
            Console.WriteLine("Total entries" + total);
        }

        static List<List<KeyValuePair<int, double>>> CreateTestVectors()
        {
            string nonspamTestFolderPath = "nonspam-test";
            string spamTestFolderPath = "spam-test";

            List<string> documents = ReadTestFiles(spamTestFolderPath, nonspamTestFolderPath);

            List<List<KeyValuePair<int, double>>> vectorSearchText = TFIDF.Transform(documents.ToArray(), 0);
            //vectorSearchText = TFIDF.Normalize(vectorSearchText);

            return vectorSearchText;
        }
        static List<string> ReadTestFiles(string spamTestFilePath, string nonspamTestFilePath)
        {
            List<string> documents = new List<string>();

            foreach (string file in Directory.GetFiles(nonspamTestFilePath, "*.txt"))
            {
                string text = File.ReadAllText(file);
                documents.Add(text);
                nonspamNumber++;
            }
            foreach (string file in Directory.GetFiles(spamTestFilePath, "*.txt"))
            {
                string text = File.ReadAllText(file);
                documents.Add(text);
            }

            return documents;
        }
        static C_SVC TrainSVM(string trainFile)
        {
            var data_set = ProblemHelper.ReadProblem(trainFile);
            return new C_SVC(data_set, KernelHelper.LinearKernel(), 1);
        }
        static List<string> GetTrainDocuments(string spamTrainFilePath, string nonspamTrainFilePath)
        {
            List<string> documents = new List<string>();

            foreach (string file in Directory.GetFiles( nonspamTrainFilePath, "*.txt"))
            {
                string text = File.ReadAllText(file);
                documents.Add(text);
                nonspamNumber++;
            }
            foreach (string file in Directory.GetFiles(spamTrainFilePath, "*.txt"))
            {
                string text = File.ReadAllText(file);
                documents.Add(text);
            }

            return documents;
        }
        static void CreateProblemFile(string filePath)
        {
            string nonspamFolderPath = "nonspam-train";
            string spamFolderPath = "spam-train";

            List<string> documents = GetTrainDocuments(spamFolderPath, nonspamFolderPath);

            // Apply TF*IDF to the documents and get the resulting vectors.
            List<List<KeyValuePair<int, double>>> vectorText = TFIDF.Transform(documents.ToArray(), 0);
            vectorText = TFIDF.Normalize(vectorText);

            WriteProblemFile(filePath, vectorText);
        }
        static void WriteProblemFile(string filePath, List<List<KeyValuePair<int,double>>> vectorText){
            string labelValue = "+1";
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(filePath))
            {
                foreach (var lineVector in vectorText)
                {
                    nonspamNumber--;
                    if (nonspamNumber == 0) { labelValue = "-1"; };
                    string lineText = VectorTextToString(labelValue, lineVector);
                    file.WriteLine(lineText);
                }
            }
        }
        static string VectorTextToString(string labelValue, List<KeyValuePair<int, double>> vectorText)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(labelValue);
            builder.Append(" ");

            foreach(var entity in vectorText)
            {
                builder.Append(entity.Key);
                builder.Append(":");
                builder.Append(entity.Value);
                builder.Append(" ");
            }

            return builder.ToString();
        }
    }
}
